package de.mmis.core.base.abstracttree.serializer.selector;

import java.util.Map;

import de.mmis.core.base.abstracttree.Tree;
import de.mmis.core.base.gclass.GClass;

/**
 * abstract superclass of all instance selectors used in the second phase of
 * deserialization. It receives the target type and constructs the final
 * deserialized object
 * 
 * @author Christian Koch
 */
public abstract class InstanceSelector {

	/**
	 * {@link Exception} thrown when the instance selection fails
	 * 
	 * @author Christian Koch
	 */
	public class InstanceSelectorException extends Exception {
		private static final long serialVersionUID = 4443103786363902476L;

		public InstanceSelectorException() {
			super();
		}

		public InstanceSelectorException(String message) {
			super(message);
		}

		public InstanceSelectorException(Throwable cause) {
			super(cause);
		}

		public InstanceSelectorException(String message, Throwable cause) {
			super(message, cause);
		}
	}

	private final String id;

	/**
	 * @return reference id that was wrapped around this {@link Tree} and that
	 *         should be added to the reference map using the method setID() as
	 *         soon as the final object is created
	 */
	public String getID() {
		return this.id;
	}

	private final Map<String, Object> idmap;

	/**
	 * @return reference map containing the previously deserialized objects
	 */
	public Map<String, Object> getIDMap() {
		return this.idmap;
	}

	/**
	 * inserts the reference ID into the reference map using the given object as
	 * value. This method should be called as soon as the final java obect is
	 * created and before further object initialization is done, to allow the
	 * deserializations used in the initialization code to use the reference.
	 * 
	 * @param object
	 *            the final deserialized object
	 */
	public void setID(Object object) {
		if (this.id != null && this.idmap != null)
			this.idmap.put(this.id, object);
	}

	/**
	 * cerate a new {@link InstanceSelector}
	 * 
	 * @param id
	 *            the ID that should be added to the reference map as soon as
	 *            the final object is created
	 * @param idmap
	 *            the reference map containing previously deserialized objects
	 */
	public InstanceSelector(String id, Map<String, Object> idmap) {
		this.id = id;
		this.idmap = idmap;
	}

	/**
	 * create the final deserialized {@link Object} given the target type
	 * 
	 * @param gclass
	 *            the target type the final object should fit
	 * @return the final deserialized object
	 * @throws InstanceSelectorException
	 */
	public abstract Object createInstance(GClass gclass)
			throws InstanceSelectorException;

}
